package com.scors.logos.jpa.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.scors.logos.jpa.PersistenceJPAGeneric;

@Transactional(propagation = Propagation.NESTED)
public class PersistenceJPAGenericImpl<T> implements PersistenceJPAGeneric<T> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    protected static final Log log = LogFactory.getLog(UserDaoImpl.class);

    protected final Class<T> entityClass;

    public PersistenceJPAGenericImpl(Class<T> entityClass) {
	this.entityClass = entityClass;
    }

    @PersistenceContext(name = "MyPersistenceUnit")
    protected EntityManager entityManager;

    /**
     * {@inheritDoc}
     */
    @Override
    public void persist(T transientUser)  {
	log.debug("persisting UserImpl instance");
	try {
	    entityManager.persist(transientUser);
	    log.debug("persist successful");
	} catch (RuntimeException re) {
	    log.error("persist failed", re);
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void remove(T persistentUser) {
	log.debug("removing UserImpl instance");
	try {
	    entityManager.remove(persistentUser);
	    log.debug("remove successful");
	} catch (RuntimeException re) {
	    log.error("remove failed", re);
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void remove(Integer userId) {
	this.remove(this.findById(userId));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T merge(T detachedUser) {
	log.debug("merging UserImpl instance");
	try {
	    T result = entityManager.merge(detachedUser);
	    log.debug("merge successful");
	    return result;
	} catch (RuntimeException re) {
	    log.error("merge failed", re);
	    return null;
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T findById(Integer id) {
	log.debug("getting UserImpl instance with id: " + id);
	try {
	    T instance = entityManager.find(entityClass, id);
	    log.debug("findById successful");
	    return instance;
	} catch (RuntimeException re) {
	    log.error("findById failed", re);
	    return null;
	}
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll() {
	log.debug("getting all UserImpl instances");
	try {
	    Query query = entityManager.createQuery("select u from "+entityClass.getSimpleName()+" u");
	    List<T> userList = query.getResultList();
	    log.debug("findAll successful");
	    return userList;
	} catch (RuntimeException re) {
	    log.error("findAll failed", re);
	    return new ArrayList<T>();
	}
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<T> search(String searchString) {
	log.debug("Search UserImpl instances with search string: "
		+ searchString);
	try {
	    Query query = entityManager
		    .createQuery("select u from UserImpl u where u.login like :searchString or u.fullname like :searchString");
	    query.setParameter("searchString", searchString);
	    @SuppressWarnings("unchecked")
	    List<T> userList = query.getResultList();
	    log.debug("search successful");
	    return userList;
	} catch (RuntimeException re) {
	    log.error("search failed", re);
	    return new ArrayList<T>();
	}
    }

    @Override
    public EntityManager getEntityManager() {
	return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
	this.entityManager = entityManager;
    }

}
